﻿#pragma once
#ifndef MEMORY_//由W意波(LuoJun)编写
#define MEMORY_
#ifdef _LINUX
#include <unistd.h>
inline void Sleep(size_t t) { usleep(t * 1000); }
#endif

namespace LK
{
	//#define LJ_MEMORY_TEST//越界检测
#ifdef LJ_MEMORY_TEST
#define LJ_MEMORY_TEST_BEFORE 16//前置16字节检测
#define LJ_MEMORY_TEST_AFTER 16//后置16字节检测
#define LJ_MEMORY_TEST_MASK 0xff//检测掩码0xff
	void* LJ_MEMORY_TEST_CHECK(void*p);
#endif
	/**
	@brief 包含内存字节操作相关静态函数*/
	struct Memory
	{
		/**
		@brief 复制内存
		@param [传入,写出]参数pDestination指向目标内存
		@param [传入]参数pSource指向源数据内存
		@param [传入]参数sizeInBytes是按字节数表示的大小
		@note 源数据数和目标内存不能重叠*/
		static void Copy(void* pDestination, const void* pSource, size_t SizeInBytes);
		/**
		@brief 移动内存（内存复制的可能有重叠版本）
		@param [传入,写出]参数pDestination指向目标内存
		@param [传入]参数pSource指向源数据内存
		@param [传入]参数sizeInBytes是按字节数表示的大小
		@note 源数据数和目标内存区域可以重叠*/
		static void Move(void* pDestination, const void* pSource, size_t sizeInBytes);
		/**
		@brief 分配Length个元素T所需的内存空间
		@param [传入]参数Length表示申请的元素数
		@return 返回申请内存首地址
		@note 使用方法如 int*p = Malloc<int>(12);
		@exception内存分配失败时将抛出异常@class XOutOfMemoryException*/
		template<class T>static T* Malloc(size_t Length) { return (T*)Malloc(sizeof(T), Length); }
		/**
		@brief 分配Length个元素T所需的内存空间
		@param [传入]参数Length表示申请的元素数
		@param [写出]参数pMaxSize用以写出实际分配元素数
		@return 返回申请内存首地址
		@note 使用方法如 size_t maxs;int*p = Malloc<int>(12,&maxs);
		@exception内存分配失败时将抛出异常@class XOutOfMemoryException*/
		template<class T>static T* Malloc(size_t Length, size_t*pMaxSize) { return (T*)Malloc(sizeof(T), Length, pMaxSize); }
		/**
		@brief重新分配Length个元素T所需的内存空间
		@param [传入]参数p表示原分配内存首地址，该内存必须由Malloc函数分配
		@param [传入]参数Length表示所需元素数
		@return 返回新分配内存的首地址
		@eception 当重新分配失败时将抛出异常@class XOutOfMemoryException
		@note 如果传入参数p为NULL，那么Realloc的功能跟Malloc一样。分配成功时，内容将进行自动复制*/
		template<class T>static T* Realloc(T* p, size_t Length) { return (T*)Realloc(p, sizeof(T), Length); }
		/**
		@brief 使用new分配空间，并在失败时抛出XOutOfMemoryException异常
		@param [传入]参数Length表示所需元素数
		@return 返回新分配内存的首地址
		@eception 当分配失败时将抛出异常@class XOutOfMemoryException*/
		template<class T>static T*New(size_t Length);
		/**
		@brief 使用new分配空间，并在失败时抛出XOutOfMemoryException异常
		@param [传入]参数Length表示所需元素数
		@param [写出]参数outSize表示实际分配的可用元素数
		@return 返回新分配内存的首地址
		@eception 当分配失败时将抛出异常@class XOutOfMemoryException*/
		template<class T>static T*New(size_t Length, size_t* outSize);
		/**
		@brief 释放内存
		@param [传入]参数p指向需要释放的内存
		@note p所指向的内存必须是由Malloc或者Realloc分配的，当p为NULL时将立即返回
		@warning 当释放内存发生异常时，将直接导致程序终止*/
		template<class T>static void Free(T*p) { vFree(p); }
		/**
		@brief 调用析构函数并释放内存
		@param [传入]参数p指向需要释放的内容
		@note p所指向的内存必须是由Memory::New分配的，当p为NULL时将立即返回
		@warning 当释放内存发生异常时，将直接导致程序终止*/
		template<class T>static void Delete(T*p) { delete[]p; }
		/**
		@brief 获取一个临时数组以独占使用
		@param [传入]参数count表示需要的最小字节数量
		@param [写出]参数pPointer用以写出一个unsigned char指针，指向临时数组
		@return 返回一个独占标记，用以在ReleaseBuffer时释放对临时内存的独占使用
		@note 使用完请使用ReleaseBuffer析构
		@note 该方法线程安全*/
		static size_t GetBuffer(size_t count, unsigned char**pPointer);
		/**
		@brief 释放一个独占使用的临时数组
		@param [传入]参数mask为独占使用标记
		@param [传入]参数pointer指向临时数组
		@note 该方法线程安全*/
		static void ReleaseBuffer(size_t mask, unsigned char*pointer);
		/**
		@brief 计算申请内存大小
		@param [传入]参数s表示至少需要申请的内存大小
		@return 返回值为建议申请的内存大小
		@note 该方法线程安全*/
		static inline size_t GetResize(size_t s) { return  (((size_t)1) << (sizeof(size_t) * 8 - Bits::LeftZeroCount(s + sizeof(size_t) * 4))) - sizeof(size_t) * 4; }
		/**
		@brief 删除未被使用的临时数组
		@note 该方法线程安全*/
		static void ClearNotUsingBuffers();
	private:

		static void* GetDefaultBuffer();
		static void vFree(void*p);
		static void* Malloc(size_t size, size_t Length);
		static void* Malloc(size_t size, size_t Length, size_t*ps);
		static void* Realloc(void* p, size_t size, size_t Length);
	};
}
#endif
